/*
 *      Copyright (C) 2005-2011 Team XBMC
 *      http://www.xbmc.org
 *
 *  This Program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2, or (at your option)
 *  any later version.
 *
 *  This Program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with XBMC; see the file COPYING.  If not, write to
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
 *  http://www.gnu.org/copyleft/gpl.html
 *
 */

#include <string.h>
#include "platform/threads/threads.h"
#include "platform/sockets/tcp.h"
#include "platform/util/util.h"
#include "platform/threads/mutex.h"
#include "PVREtpProtocol.h"
#include "lib/protocol.h"
#include "lib/device.h"
#include "client.h"

using namespace std;
using namespace ADDON;
using namespace PLATFORM;

#define		ETP_INIT_STR			"eTUNER V001 \n\n"
#define		ETP_STR_SZ				1024

PVREtpProtocol::PVREtpProtocol(CStdString host, uint16_t port)
{
	XBMC->Log(LOG_DEBUG,"PVREtpProtocol: %s %d\n", host.c_str(), port);
	m_strRemoteIP = host;
	m_iRemoteMainPort = port;
	m_iRemoteDataPort = 0;

	m_TcpMain = NULL;
	m_TcpRec = NULL;
	m_TcpTimers = NULL;
	m_TcpEPG = NULL;
	m_TcpChan = NULL;
	m_TcpData = NULL;
}

PVREtpProtocol::~PVREtpProtocol(void)
{
	CloseStream();
}

/* Stream stuff, live and recorded */

ssize_t PVREtpProtocol::ReadBytesFromStream(uint8_t *data, uint32_t data_sz)
{
//	PLATFORM::CLockObject lock(m_mutex);
	if (IsStreaming() && m_TcpMain)
		return m_TcpMain->Read(data, data_sz, 0);
	return -1;
}


bool PVREtpProtocol::StreamSetTimePosDone(bool stat)
{
	bool ret = false;
	if (IsStreaming())
	{
		//0xEE = bad, 0xDE = good
		uint8_t tmp = 0xDE;
		if (stat == false)
			tmp=0xEE;

		if (m_TcpData->Send8(&tmp) == sizeof(tmp))
			return true;
	}
	return ret;
}

uint64_t PVREtpProtocol::StreamSetTimePos(uint64_t pos)
{
	uint64_t ret = 0;
//	PLATFORM::CLockObject lock(m_mutex);

	if (IsStreaming())
	{
//		XBMC->Log(LOG_DEBUG,"PVREtpProtocol::StreamSetTimePos\n");
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_SET_STREAM_POS;
		pstruct.dataptr_size = sizeof(pos);
		pstruct.dataptr = (uint8_t*)&pos;

		if (m_TcpMain->SendProtocolCMD(&pstruct) == true)
		{

			int rc = m_TcpData->Get64((uint8_t*)&ret);

			if (!(rc == sizeof(ret)))
			{
				ret = -1;
			}
		}
	}
	return ret;
}
uint64_t PVREtpProtocol::StreamGetTimePos(void)
{
//	PLATFORM::CLockObject lock(m_mutex);
	return Get64Stream(PROTO_GET_STREAM_POS);
}

uint64_t PVREtpProtocol::StreamGetTimeEnd(void)
{
//	PLATFORM::CLockObject lock(m_mutex);
	return Get64Stream(PROTO_GET_STREAM_END_POS);
}

uint64_t PVREtpProtocol::StreamGetTimeStart(void)
{
//	PLATFORM::CLockObject lock(m_mutex);
	return Get64Stream(PROTO_GET_STREAM_START_POS2);
}


bool PVREtpProtocol::TuneGetCtrlPort(void)
{
	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::TuneGetCtrlPort start\n");
//	PLATFORM::CLockObject lock(m_mutex);
	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::TuneGetCtrlPort 1\n");

	if (m_TcpMain && m_TcpMain->Get16((uint8_t*)&m_iRemoteDataPort) == sizeof(uint16_t))
	{
	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::TuneGetCtrlPort 2\n");
		if (m_iRemoteDataPort)
		{
	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::TuneGetCtrlPort 3\n");

			m_TcpData = new PVREtpSocket(m_strRemoteIP, m_iRemoteDataPort);
	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::TuneGetCtrlPort 4\n");

			if (m_TcpData && m_TcpData->Open())
			{
				XBMC->Log(LOG_DEBUG,"Data Port Opened: %d\n", m_iRemoteDataPort);
				return true;
			}
		}
	}
	XBMC->Log(LOG_DEBUG,"Data Port NOT Opened\n");

	return false;
}

bool PVREtpProtocol::CloseStream(void)
{
//	PLATFORM::CLockObject lock(m_mutex);
//	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::CloseStream1\n");
	if (m_TcpMain)
	{
		m_TcpMain->Close();
//		m_ReadCloseLock
//		delete m_TcpMain;
//		m_TcpMain = NULL;
	}

	if (m_TcpData)
	{
		if (m_TcpData->Open())
			m_TcpData->Close();
		delete m_TcpData;
	}
	m_TcpData = NULL;
	m_iRemoteDataPort = 0;

	if (m_TcpRec) delete m_TcpRec;
	m_TcpRec = NULL;

	if (m_TcpEPG) delete m_TcpEPG;
	m_TcpEPG = NULL;

	if (m_TcpChan) delete m_TcpChan;
	m_TcpChan = NULL;

	if (m_TcpTimers) delete m_TcpTimers;
	m_TcpTimers = NULL;

//	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::CloseStream2\n");
	return true;
}

bool PVREtpProtocol::IsStreaming(void)
{
//	return (m_TcpMain && m_TcpMain->IsOpen() && m_TcpData && m_TcpData->IsOpen());
//	PLATFORM::CLockObject lock(m_mutex);
	return (m_TcpMain && m_TcpMain->IsOpen());
}

bool PVREtpProtocol::TuneStream(uint32_t id)
{
	bool ret = false;
//	PLATFORM::CLockObject lock(m_mutex);

	if (m_TcpMain)
	{
		delete m_TcpMain;
	}
	m_TcpMain = new PVREtpSocket(m_strRemoteIP, m_iRemoteMainPort);

	if (m_TcpMain)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_TUNE_AND_STREAM;
		pstruct.dataptr_size = sizeof(id);
		pstruct.dataptr = (uint8_t*)&id;

		return m_TcpMain->SendProtocolCMD(&pstruct);
	}
	return ret;
}

bool PVREtpProtocol::TuneRecording(uint32_t id)
{
	bool ret = false;
//	PLATFORM::CLockObject lock(m_mutex);
	m_TcpMain = new PVREtpSocket(m_strRemoteIP, m_iRemoteMainPort);

	if (m_TcpMain)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_REC_PLAY;
		pstruct.dataptr_size = sizeof(id);
		pstruct.dataptr = (uint8_t*)&id;
		return m_TcpMain->SendProtocolCMD(&pstruct);
	}
	return ret;
}

bool PVREtpProtocol::GetStreamInfo(void)
{
	bool ret = false;
	m_mutex.Lock();

	if (IsStreaming())
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_QUERY_STREAM_INFO;

		XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetStreamInfo\n");
		return m_TcpMain->SendProtocolCMD(&pstruct);
	}

	return ret;
}

bool PVREtpProtocol::GetStreamInfoNext(TUNER_STREAM_STRUCT *info)
{
	if (IsStreaming() && m_TcpData && m_TcpData->IsOpen() && info)
	{
		ssize_t rc = m_TcpData->Read(info, sizeof(TUNER_STREAM_STRUCT), 0);
		if (rc == sizeof(TUNER_STREAM_STRUCT))
			return true;
	}
	return false;
}

void PVREtpProtocol::GetStreamInfoDone(void)
{
	m_mutex.Unlock();
}


bool PVREtpProtocol::SendKeepAlive(void)
{
	if (IsStreaming())
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_KEEP_ALIVE;
//		XBMC->Log(LOG_DEBUG,"PVREtpProtocol::SendKeepAlive\n");
		return m_TcpMain->SendProtocolCMD(&pstruct);
	}
	return false;
}

bool PVREtpProtocol::Ping(void)
{
	uint8_t ret = Get8NoStream(PROTO_INIT_CONNECTION);
	if (ret == PROTOCOL_INIT_GOOD)
		return true;
	return false;
}


/* EPG */
uint64_t PVREtpProtocol::GetEPG(char *channel_id)
{
	uint64_t ret = 0;
	XBMC->Log(LOG_DEBUG, "GetEPG -- Start\n");
	m_TcpEPG = new PVREtpSocket(m_strRemoteIP, m_iRemoteMainPort);

	XBMC->Log(LOG_DEBUG, "GetEPG -- 1\n");
	if (m_TcpEPG && channel_id)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_GET_CHAN_EPG;
		pstruct.dataptr = (uint8_t*)channel_id;
		pstruct.dataptr_size = strlen(channel_id) + 1;
	XBMC->Log(LOG_DEBUG, "GetEPG -- 2\n");

		if (m_TcpEPG->SendProtocolCMD(&pstruct) == true)
		{
	XBMC->Log(LOG_DEBUG, "GetEPG -- 3\n");

			int rc;
			rc = m_TcpEPG->Get64((uint8_t*)&ret);
	XBMC->Log(LOG_DEBUG, "GetEPG -- 4: %d (%" PRId64")\n", rc, ret);

			if (rc != sizeof(ret))
				ret = 0;
		}
		else
		{
	XBMC->Log(LOG_DEBUG, "GetEPG -- 5\n");

			GetEPGDone();
			ret = 0;
		}
	XBMC->Log(LOG_DEBUG, "GetEPG -- 6\n");

	}
	XBMC->Log(LOG_DEBUG, "GetEPG -- done: %" PRId64"\n", ret);

	return ret;
}

bool PVREtpProtocol::GetEPGNext(TIMER_STRUCT_SEND *p_timer, TIMER_STRUCT_EXTRA *extra)
{
	if (m_TcpEPG && p_timer && extra)
	{
		ssize_t rc = m_TcpEPG->Read(p_timer, sizeof(TIMER_STRUCT_SEND), 0);
		if (rc == sizeof(TIMER_STRUCT_SEND))
		{
			rc = m_TcpEPG->Read(extra, sizeof(TIMER_STRUCT_EXTRA), 0);

			if (rc == sizeof(TIMER_STRUCT_EXTRA))
				return true;
		}
	}
	return false;
}

void PVREtpProtocol::GetEPGDone(void)
{
	if (m_TcpEPG)
	{
		delete m_TcpEPG;
		m_TcpEPG = NULL;
	}
}

/* Timer */

uint64_t PVREtpProtocol::GetTimerSeqNum(void)
{
	return Get64NoStream(PROTO_GET_TIMER_SEQNUM);
}

int PVREtpProtocol::GetTimerCount(void)
{
	return Get32NoStream(PROTO_QUERY_TIMER_COUNT);
}

uint32_t PVREtpProtocol::GetTimerList(void)
{
	uint32_t ret = 0;
	m_TcpTimers = new PVREtpSocket(m_strRemoteIP, m_iRemoteMainPort);

	if (m_TcpTimers)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_QUERY_TIMER_LIST;

		if (m_TcpTimers->SendProtocolCMD(&pstruct))
		{
			if (!(m_TcpTimers->Get32((uint8_t*)&ret) == sizeof(uint32_t)))
				ret = 0;
		}
		else
		{
			GetTimerListDone();
		}
	}
	return ret;
}

bool PVREtpProtocol::GetTimerListNext(TIMER_STRUCT_SEND *p_timer)
{
	if (m_TcpTimers && p_timer)
	{
		ssize_t rc = m_TcpTimers->Read(p_timer, sizeof(TIMER_STRUCT_SEND), 0);
		if (rc == sizeof(TIMER_STRUCT_SEND))
			return true;
	}
	return false;
}

void PVREtpProtocol::GetTimerListDone(void)
{
//	m_mutex.Unlock();

	if (m_TcpTimers)
	{
		delete m_TcpTimers;
		m_TcpTimers = NULL;
	}
}

bool PVREtpProtocol::DeleteTimer(uint32_t index)
{
	return DeleteTimerRecording(PROTO_TIMER_DEL, index);
}

bool PVREtpProtocol::AddTimer(TIMER_STRUCT_SEND * timer)
{
	bool ret = false;
	PVREtpSocket *sock = new PVREtpSocket(m_strRemoteIP, (uint16_t)m_iRemoteMainPort);

	if (sock)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_TIMER_ADD;
		pstruct.dataptr = (uint8_t *)timer;
		pstruct.dataptr_size = sizeof(*timer);

		if (sock->SendProtocolCMD(&pstruct) == true)
		{
			uint8_t tmp = 0;
			if (sock->Get8((uint8_t*)&tmp) == sizeof(tmp))
			{
				if (tmp == PROTOCOL_INIT_GOOD)
					ret = true;

			}
		}
	}
	XBMC->Log(LOG_DEBUG,"Add Tiemr good: %d\n",ret);
	return ret;
}

bool PVREtpProtocol::UpdateTimer(TIMER_STRUCT_SEND * timer)
{
	return false;
}



/* Recordings */

uint64_t PVREtpProtocol::GetRecordingSeqNum(void)
{
	return Get64NoStream(PROTO_GET_REC_SEQNUM);
}

int PVREtpProtocol::GetRecordingCount(void)
{
	return Get32NoStream(PROTO_QUERY_REC_COUNT);
}

uint32_t PVREtpProtocol::GetRecordingList(void)
{
	uint32_t ret = 0;
	m_TcpRec = new PVREtpSocket(m_strRemoteIP, m_iRemoteMainPort);

	if (m_TcpRec)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_QUERY_REC_LIST;
//		XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetRecordingList\n");
		if (m_TcpRec->SendProtocolCMD(&pstruct))
		{
			if (!(m_TcpRec->Get32((uint8_t*)&ret) == sizeof(uint32_t)))
				ret = 0;
		}
		else
		{
			GetRecordingListDone();
		}
	}
	return ret;
}

bool PVREtpProtocol::GetRecordingListNext(TIMER_STRUCT_SEND *p_timer)
{
	if (m_TcpRec && p_timer)
	{
		ssize_t rc = m_TcpRec->Read(p_timer, sizeof(TIMER_STRUCT_SEND), 0);
		if (rc == sizeof(TIMER_STRUCT_SEND))
			return true;
	}
	return false;
}

void PVREtpProtocol::GetRecordingListDone(void)
{
//	m_mutex.Unlock();

	if (m_TcpRec)
	{
		delete m_TcpRec;
		m_TcpRec = NULL;
	}
}

bool PVREtpProtocol::DeleteRecording(uint32_t index)
{
	return DeleteTimerRecording(PROTO_REC_DEL, index);
}


/* Channels */

int PVREtpProtocol::GetChannelCount(void)
{
	return Get32NoStream(PROTO_QUERY_CHANNEL_COUNT);
}

bool PVREtpProtocol::GetChannelList(void)
{
	m_TcpChan = new PVREtpSocket(m_strRemoteIP, m_iRemoteMainPort);
//	XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetChannelList2\n");

	if (m_TcpChan)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = PROTO_QUERY_CHANNEL_LIST;
		return m_TcpChan->SendProtocolCMD(&pstruct);
	}
	return false;
}

bool PVREtpProtocol::GetChannelListNext(PROTOCOL_CHANNEL_STRUCT *p_channel)
{
	if (m_TcpChan && p_channel)
	{
		ssize_t rc = m_TcpChan->Read(p_channel, sizeof(PROTOCOL_CHANNEL_STRUCT), 0);
		if (rc == sizeof(PROTOCOL_CHANNEL_STRUCT))
			return true;
	}
	return false;
}
void PVREtpProtocol::GetChannelListDone(void)
{
//	m_mutex.Unlock();

	if (m_TcpChan)
	{
		delete m_TcpChan;
		m_TcpChan = NULL;
	}
}

uint8_t PVREtpProtocol::Get8NoStream(uint8_t type)
{
	uint8_t ret = -1;
	GetNoStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}

uint16_t PVREtpProtocol::Get16NoStream(uint8_t type)
{
	uint16_t ret = -1;
	GetNoStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}

uint32_t PVREtpProtocol::Get32NoStream(uint8_t type)
{
	uint32_t ret = -1;
	GetNoStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}

uint64_t PVREtpProtocol::Get64NoStream(uint8_t type)
{
	uint64_t ret = -1;
	GetNoStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}


bool PVREtpProtocol::GetStreamResp(uint8_t type, uint8_t *data, int sz)
{
	bool ret = false;
//	PLATFORM::CLockObject lock(m_mutex);
	if (IsStreaming())
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = type;

//		XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetStreamResp\n");
		if (m_TcpMain->SendProtocolCMD(&pstruct) == true)
		{
			ssize_t rc = 0;

			ret = true;

			if (sz == sizeof(uint8_t))
				rc = m_TcpData->Get8(data);
			else if (sz == sizeof(uint16_t))
				rc = m_TcpData->Get16(data);
			else if (sz == sizeof(uint32_t))
				rc = m_TcpData->Get32(data);
			else if (sz == sizeof(uint64_t))
				rc = m_TcpData->Get64(data);
			else
				ret = false;

			if (ret == false)
				XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetConnectedNoData is sads: %"PRId64"\n", rc);
		}
		else
		{
			XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetStreamResp, Send was bad: 0x%x\n", type);
		}
	}
//	else
//		XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetStreamResp -- Not Streaming\n");
	return ret;
}


uint8_t PVREtpProtocol::Get8Stream(uint8_t type)
{
	uint8_t ret = -1;
	GetStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}

uint16_t PVREtpProtocol::Get16Stream(uint8_t type)
{
	uint16_t ret = -1;
	GetStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}

uint32_t PVREtpProtocol::Get32Stream(uint8_t type)
{
	uint32_t ret = -1;
	GetStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}

uint64_t PVREtpProtocol::Get64Stream(uint8_t type)
{
	uint64_t ret = -1;
	GetStreamResp(type, (uint8_t*)&ret, sizeof(ret));
	return ret;
}

bool PVREtpProtocol::GetNoStreamResp(uint8_t type, uint8_t *data, int sz)
{
	bool ret = false;
	PVREtpSocket *sock = new PVREtpSocket(m_strRemoteIP, (uint16_t)m_iRemoteMainPort);

	if (sock && data && sz)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		memset(&pstruct, 0, sizeof(pstruct));

		pstruct.cmd = type;

		if (sock->SendProtocolCMD(&pstruct) == true)
		{
//			XBMC->Log(LOG_DEBUG,"GOOD1: 0x%x (sz: %d)\n", pstruct.cmd, sz);
			ssize_t rc = 0;
			ret = true;

			if (sz == sizeof(uint8_t))
				rc = sock->Get8(data);
			else if (sz == sizeof(uint16_t))
				rc = sock->Get16(data);
			else if (sz == sizeof(uint32_t))
				rc = sock->Get32(data);
			else if (sz == sizeof(uint64_t))
				rc = sock->Get64(data);
			else
				ret = false;
//		XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetNoStreamResp6\n");

			if (ret == false)
				XBMC->Log(LOG_DEBUG,"PVREtpProtocol::GetNoStreamRespNoData is sads: %" PRId64"\n", rc);
		}
		else
		{
			XBMC->Log(LOG_DEBUG,"OH NO, GetNoStreamResp: 0x%x\n", type);
		}

		delete sock;
	}
	else
	{
		XBMC->Log(LOG_DEBUG,"UGGHH\n");
	}
	return ret;
}


bool PVREtpProtocol::DeleteTimerRecording(uint8_t cmd, uint32_t index)
{
	bool ret = false;
	PVREtpSocket *sock = new PVREtpSocket(m_strRemoteIP, (uint16_t)m_iRemoteMainPort);

	if (sock)
	{
		PROTOCOL_CMD_STRUCT pstruct = {0};
		pstruct.cmd = cmd;
		pstruct.dataptr = (uint8_t *)&index;
		pstruct.dataptr_size = sizeof(index);

		if (sock->SendProtocolCMD(&pstruct) == true)
		{
			uint8_t tmp = 0;
			if (sock->Get8((uint8_t*)&tmp) == sizeof(tmp))
			{
				if (tmp == PROTOCOL_INIT_GOOD)
					ret = true;

			}
		}
	}
//	XBMC->Log(LOG_DEBUG,"Del Tiemr/rec good: %d\n",ret);
	return ret;
}

void PVREtpProtocol::Flush(void)
{
	if (m_TcpMain && m_TcpMain->IsOpen())
	{
		m_TcpMain->Flush();
	}
}


// *********************************************

ssize_t PVREtpSocket::Send8(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Send8\n");
	if (data)
		return SendDataSize(data, sizeof(uint8_t));
	return 0;
}

ssize_t PVREtpSocket::Send16(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Send16\n");
	if (data)
		return SendDataSize(data, sizeof(uint16_t));
	return 0;
}

ssize_t PVREtpSocket::Send32(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Send32\n");
	if (data)
		return SendDataSize(data, sizeof(uint32_t));
	return 0;
}

ssize_t PVREtpSocket::Send64(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Send64\n");
	if (data)
		return SendDataSize(data, sizeof(uint64_t));
	return 0;
}


ssize_t PVREtpSocket::SendDataSize(uint8_t *data, int data_sz)
{
    if (IsOpen() && data && data_sz)
        return Write(data, data_sz);
    return 0;
}


ssize_t PVREtpSocket::Get8(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Get8\n");
	if (data)
		return GetDataSize(data, sizeof(uint8_t));
	return 0;
}

ssize_t PVREtpSocket::Get16(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Get16\n");
	if (data)
		return GetDataSize(data, sizeof(uint16_t));
	return 0;
}

ssize_t PVREtpSocket::Get32(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Get32\n");
	if (data)
		return GetDataSize(data, sizeof(uint32_t));
	return 0;
}

ssize_t PVREtpSocket::Get64(uint8_t *data)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket::Get64\n");
	if (data)
		return GetDataSize(data, sizeof(uint64_t));
	return 0;
}

ssize_t PVREtpSocket::GetDataSize(uint8_t *data, int data_sz)
{
    if (IsOpen() && data && data_sz)
        return Read(data, data_sz,  m_RWTimeout);
    return 0;
}

bool PVREtpSocket::SendProtocolCMD(PROTOCOL_CMD_STRUCT *protocol)
{
	if (IsOpen() == false)
		Connect();

	if (IsOpen() && protocol)
	{
		ssize_t rc = 0;
		uint32_t _send = (PROTO_CMD_START | protocol->cmd);

		rc = Write(&_send, sizeof(_send));

		if (rc != sizeof(_send))
		{
			XBMC->Log(LOG_DEBUG,"PVREtpSocket::SendProtocolCMD - Error 1\n");
			return false;
		}

		if (protocol->dataptr_size)
		{
			rc = Write(&protocol->dataptr_size, sizeof(protocol->dataptr_size));
			if (rc != sizeof(protocol->dataptr_size))
			{
				XBMC->Log(LOG_DEBUG,"PVREtpSocket::SendProtocolCMD - Error 2\n");
				return false;
			}

			rc = Write(protocol->dataptr, protocol->dataptr_size);
			if (rc != (ssize_t)protocol->dataptr_size)
			{
				XBMC->Log(LOG_DEBUG,"PVREtpSocket::SendProtocolCMD - Error 3\n");
				return false;
			}

		}
		return true;
	}
	XBMC->Log(LOG_DEBUG,"PVREtpSocket::SendProtocolCMD - Error 4 (%d)\n", IsOpen());
	return false;
}

bool PVREtpSocket::Connect(void)
{
	if (Open(m_OpenTimeout))
	{
		ssize_t rc = 0;
		uint8_t req[ETP_STR_SZ] = {0};
		int len = strlen(ETP_INIT_STR);

		snprintf((char*)req, ETP_STR_SZ-1, "%s", ETP_INIT_STR);
		rc = Write(req, len);

		if (rc != (ssize_t)len)
		{
			XBMC->Log(LOG_DEBUG,"[ETP_P] ConnectMain bad1: %" PRId64" %d (%s)\n", rc, len, GetError().c_str());
			Close();
		}
		else
		{
			memset(req, 0, ETP_STR_SZ);
//			rc = Read(req, 1, m_RWTimeout);
			rc = Read(req, 1, 0);
			if (rc != 1)
			{
				XBMC->Log(LOG_DEBUG,"[ETP_P] ConnectMain bad2: %" PRId64" %d (%s)\n", rc, len, GetError().c_str());
				Close();
			}
			else if (req[0] == PROTOCOL_INIT_GOOD)
			{
//				XBMC->Log(LOG_DEBUG,"[ETP_P] ConnectMain Good!\n");
				return true;
			}
		}
	}
	return false;
}

void PVREtpSocket::Flush(void)
{
	if (IsOpen())
	{
		ssize_t flush = 0;
		uint8_t tmp = 0;
		do
		{
			flush = Read(&tmp, 1, 250);
		} while (flush > 0);
	}
}

PVREtpSocket::PVREtpSocket(const CStdString &strHostname, uint16_t iPort) : CTcpSocket(strHostname, iPort)
{
//	XBMC->Log(LOG_DEBUG,"PVREtpSocket: %s %d\n", strHostname.c_str(), iPort);
//	m_RWTimeout = 5000;
	m_RWTimeout = 0;
};

PVREtpSocket::~PVREtpSocket(void)
{
//	XBMC->Log(LOG_DEBUG,"Destroying Socket..\n");
	Close();
};
